/**
 * 控件模型类
 */
import _ from 'lodash'
import _uuid from 'lodash-uuid'

export class Row {
    constructor ({ ...args }) {
        this.rowGid = args.rowGid || _uuid.uuid()
        this.units = args.units || []
    }
    static getPropertyType (property) {
        let propertyType = 'undefined'
        switch (property) {
            case 'rowGid':
                propertyType = 'uuid'
                break
            case 'units':
                propertyType = 'array'
                break
        }
        return propertyType
    }
}

/**
 * 控件基类
 */
export class Unit {
    constructor ({ ...args }) {
        // 行主键
        this.rowGid = args.rowGid
        // 单元主键
        this.unitGid = _.isNil(args.unitGid) ? _uuid.uuid() : args.unitGid
        // 标签
        this.label = _.isNil(args.label) ? '新建控件' : args.label
        // 列宽
        this.col = _.isNil(args.col) ? 12 : args.col
        // CLASS
        this.extraClass = args.extraClass
        // ID
        this.id = args.id
        // 默认值
        this.defaultValue = args.defaultValue
        // 占位符
        this.placeholder = args.placeholder
        // 帮助文本
        this.helpText = args.helpText
        // 可见
        this.visible = _.isNil(args.visible) ? true : args.visible
        // 禁用
        this.disabled = _.isNil(args.disabled) ? false : args.disabled
        // 左补位
        this.padLeft = args.padLeft
        // 右补位
        this.padRight = args.padRight
        // 宽度
        this.width = args.width
    }
    getPropertyType (property) {
        let propertyType = 'undefined'
        switch (property) {
            case 'rowGid':
            case 'unitGid':
                propertyType = 'uuid'
                break
            case 'label':
            case 'extraClass':
            case 'id':
            case 'placeholder':
            case 'helpText':
            case 'padLeft':
            case 'padRight':
            case 'width':
                propertyType = 'string'
                break
            case 'col':
                propertyType = 'range'
                break
            case 'visible':
            case 'disabled':
                propertyType = 'boolean'
                break
        }
        return propertyType
    }
    validate (property) {
        let error = {
            code: 0,
            message: null
        }
        switch (property) {
            case 'rowGid':
            case 'unitGid':
                if (!_uuid.isUuid(this[property]) && !_.isEmpty(this[property])) {
                    error = {
                        code: -1,
                        message: `类型为 ${this.getPropertyType(property)}.`
                    }
                }
                break
            case 'label':
            case 'extraClass':
            case 'id':
            case 'placeholder':
            case 'helpText':
            case 'padLeft':
            case 'padRight':
                if (!_.isString(this[property]) && !_.isEmpty(this[property])) {
                    error = {
                        code: -1,
                        message: `类型为 ${this.getPropertyType(property)}.`
                    }
                }
                break
            case 'col':
                if (_.isNaN(this[property])) {
                    error = {
                        code: -1,
                        message: `类型为 ${this.getPropertyType(property)}.`
                    }
                }
                break
            case 'visible':
            case 'disabled':
                if (!_.isBoolean(this[property])) {
                    error = {
                        code: -1,
                        message: `类型为 ${this.getPropertyType(property)}.`
                    }
                }
                break
        }
        return error
    }
    validateAll () {
        return new Promise(resolve => {
            _.chain(this).keys().every(key => this.validate(key).code === 0).value()
            resolve(_.chain(this).keys().every(key => this.validate(key).code === 0).value())
        })
    }
}

/**
 * 文本输入框控件
 */
export class TextboxUnit extends Unit {
    constructor ({ ...args }) {
        super({ ...args })
        this.unitType = 'textboxUnit'
    }
    getPropertyType (property) {
        let propertyType = super.getPropertyType(property)
        switch (property) {
            case 'defaultValue':
                propertyType = 'string'; break
        }
        return propertyType
    }
    validate (property) {
        let error = super.validate(property)
        switch (property) {
            case 'defaultValue':
                if (!_.isString(this[property]) && !_.isEmpty(this[property])) {
                    error = {
                        code: -1,
                        message: `类型为 ${this.getPropertyType(property)}.`
                    }
                }
                break
        }
        return error
    }
}

/**
 * 数字输入框控件
 */
export class NumericTextboxUnit extends Unit {
    constructor ({ ...args }) {
        super({ ...args })
        this.unitType = 'numericTextboxUnit'
        this.culture = args.culture
        this.decimals = _.isNaN(args.decimals) ? 2 : args.decimals
        this.factor = _.isNaN(args.factor) ? 1 : args.factor
        this.format = _.isNil(args.format) ? 'n' : args.format
        this.min = _.isNaN(args.min) ? null : args.min
        this.max = _.isNaN(args.max) ? null : args.max
        this.round = _.isNil(args.round) ? true : args.round
        this.spinners = _.isNil(args.spinners) ? true : args.spinners
        this.step = _.isNaN(args.step) ? 1 : args.step
    }
    getPropertyType (property) {
        let propertyType = super.getPropertyType(property)
        switch (property) {
            case 'culture':
            case 'format':
                propertyType = 'string'; break
            case 'defaultValue':
            case 'decimals':
            case 'factor':
            case 'min':
            case 'max':
            case 'step':
                propertyType = 'number'; break
            case 'round':
            case 'spinners':
                propertyType = 'boolean'; break
        }
        return propertyType
    }
    validate (property) {
        let error = super.validate(property)
        switch (property) {
            case 'culture':
            case 'format':
                if (!_.isString(this[property]) && !_.isEmpty(this[property])) {
                    error = {
                        code: -1,
                        message: `类型为 ${this.getPropertyType(property)}.`
                    }
                }
                break
            case 'defaultValue':
            case 'decimals':
            case 'factor':
            case 'min':
            case 'max':
            case 'step':
                if (_.isNaN(this[property]) && !_.isEmpty(this[property])) {
                    error = {
                        code: -1,
                        message: `类型为 ${this.getPropertyType(property)}.`
                    }
                }
                break
            case 'round':
            case 'spinners':
                if (!_.isBoolean(this[property])) {
                    error = {
                        code: -1,
                        message: `类型为 ${this.getPropertyType(property)}.`
                    }
                }
                break
        }
        return error
    }
}

export class DatePickerUnit extends Unit {
    constructor ({ ...args }) {
        super({ ...args })
        this.unitType = 'datePickerUnit'
        this.culture = args.culture
        this.dateInput = _.isNil(args.dateInput) ? false : args.dateInput
        this.depth = _.isNil(args.depth) ? 'month' : args.depth
        this.start = _.isNil(args.start) ? 'month' : args.start
        this.disableDates = _.isNil(args.disableDates) ? null : args.disableDates
        this.format = _.isNil(args.format) ? 'yyyy/MM/dd' : args.format
        this.max = _.isNil(args.max) ? new Date(2099, 11, 31) : args.max
        this.min = _.isNil(args.min) ? new Date(1900, 0, 1) : args.min
        this.readonly = _.isNil(args.readonly) ? false : args.readonly
    }
    getPropertyType (property) {
        let propertyType = super.getPropertyType(property)
        switch (property) {
            case 'culture':
            case 'depth':
            case 'start':
            case 'disableDates':
            case 'format':
                propertyType = 'string'; break
            case 'defaultValue':
            case 'max':
            case 'min':
                propertyType = 'date'; break
            case 'dateInput':
            case 'readonly':
                propertyType = 'boolean'; break
        }
        return propertyType
    }
    validate (property) {
        let error = super.validate(property)
        switch (property) {
            case 'culture':
            case 'disableDates':
            case 'format':
                if (!_.isString(this[property]) && !_.isEmpty(this[property])) {
                    error = {
                        code: -1,
                        message: `类型为 ${this.getPropertyType(property)}.`
                    }
                }
                break
            case 'depth':
            case 'start':
                if (!_.isString(this[property]) && !_.isEmpty(this[property])) {
                    error = {
                        code: -1,
                        message: `类型为 ${this.getPropertyType(property)}.`
                    }
                }

                if (!_.includes(['month', 'year', 'decade', 'century'], this[property])) {
                    error = {
                        code: -2,
                        message: '可选参数: month, year, decade, century'
                    }
                }
                break
            case 'defaultValue':
                if (!_.isDate(this[property]) && !_.isEmpty(this[property])) {
                    error = {
                        code: -1,
                        message: `类型为 ${this.getPropertyType(property)}.`
                    }
                }

                if (_.isDate(this[property]) && (this[property].getTime() < this['min'].getTime() || this[property].getTime() > this['max'].getTime())) {
                    error = {
                        code: -2,
                        message: '介于最小值与最大值 (包含边界)'
                    }
                }
                break
            case 'max':
                if (_.isDate(this[property])) {
                    if (this[property].getTime() < this['min'].getTime()) {
                        error = {
                            code: -2,
                            message: '最大值必须大等于最小值'
                        }
                    }
                } else {
                    error = {
                        code: -1,
                        message: `类型为 ${this.getPropertyType(property)}.`
                    }
                }
                break
            case 'min':
                if (_.isDate(this[property])) {
                    if (this[property].getTime() > this['max'].getTime()) {
                        error = {
                            code: -2,
                            message: '最小值必须小等于最大值'
                        }
                    }
                } else {
                    error = {
                        code: -1,
                        message: `类型为 ${this.getPropertyType(property)}.`
                    }
                }

                break
            case 'dateInput':
            case 'readonly':
                if (!_.isBoolean(this[property])) {
                    error = {
                        code: -1,
                        message: `类型为 ${this.getPropertyType(property)}.`
                    }
                }
                break
        }
        return error
    }
}
